package jhunter.web.mvc;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Pattern;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import jhunter.JHunterContainer;
import jhunter.context.JHunterContext;
import jhunter.security.PermissionCheck;
import jhunter.web.mvc.interceptor.HandlerInterceptor;
import jhunter.web.mvc.params.ApplicationMap;
import jhunter.web.mvc.params.FlashManger;
import jhunter.web.mvc.params.FlashMap;
import jhunter.web.mvc.params.ParameterMap;
import jhunter.web.mvc.params.SessionMap;
import jhunter.web.mvc.view.ViewResovle;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import schema.ext.ActionExt;
import schema.ext.HttpMethod;
import schema.ext.PathInfo;

public class JHunterFilter implements Filter {

	private static Log log = LogFactory.getLog(JHunterFilter.class);

	private static final String RESOURCE_PATH = "/rs/";

	public static final String EXCLUDE_PATTERNS = "excludePatterns";

	private String defaultExcludePattens = "/static/[^\\n]*,[^\\n]*.jsp,[^\\n]*.ico,[^\\n]*.css,[^\\n]*.js,[^\\n]*.gif";

	protected List<Pattern> excludePattens = new ArrayList<Pattern>();

	private ViewResovle viewResovle;

	private FlashManger flashManger;

	private ServletContext servletContext;

	private List<HandlerInterceptor> interceptors = new ArrayList<HandlerInterceptor>();

	private PermissionCheck permissionCheck;

	private JHunterContainer jHunterContainer;

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {

		servletContext = filterConfig.getServletContext();

		viewResovle = JHunterContext.getViewResovle();
		flashManger = JHunterContext.getFlashManger();
		permissionCheck = JHunterContext.getPermissionCheck();
		jHunterContainer = JHunterContext.getJHunterContainer();

		String excludePatterns = defaultExcludePattens;
		String ext = filterConfig.getInitParameter(EXCLUDE_PATTERNS);
		if (ext != null && ext.length() > 0) {
			excludePatterns = excludePatterns + "," + ext;
		}
		if (excludePatterns != null) {
			String[] pts = excludePatterns.split(",");
			for (String p : pts) {
				excludePattens.add(Pattern.compile(p));
				log.debug("exclude pattern:" + p);
			}
		}
	}

	protected boolean matchExcude(String url) {
		for (Pattern p : excludePattens) {
			if (p.matcher(url).matches()) {
				return true;
			}
		}
		return false;
	}

	protected String getFormatUri(String uri) {
		if (uri.endsWith("/")) {
			uri = uri.substring(0, uri.length() - 1);
		}
		return uri;
	}

	protected HttpMethod getHttpMethod(HttpServletRequest req) {
		HttpMethod httpMethod = HttpMethod.getByString(req.getMethod());
		String m = req.getParameter("_method");
		if (m != null) {
			HttpMethod h = HttpMethod.getByString(m);
			if (h != null) {
				httpMethod = h;
			}
		}
		return httpMethod;
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse resp = (HttpServletResponse) response;
		String uri = req.getRequestURI();
		PathInfo pathInfo = new PathInfo(getFormatUri(uri), getHttpMethod(req));

		if (uri.startsWith(RESOURCE_PATH) && (uri.endsWith(".js") || uri.endsWith(".css") || uri.endsWith(".gif") || uri.endsWith(".png")|| uri.endsWith(".jpg"))) {
			jHunterContainer.renderStaticReousrce(uri, RESOURCE_PATH, resp);
			return;
		}
		if (!matchExcude(req.getRequestURI())) {
			ActionExt action = jHunterContainer.matchActionUri(pathInfo);
			if (action != null) {
				try {
					log.debug("uri->" + pathInfo);
					if (!permissionCheck.isPermitted(action)) {
						// NOT Permitted
						throw new RuntimeException("NOT Permitted");
					}

					response.setCharacterEncoding("utf-8");// TOOD

					ActionContext context = new ActionContext();
					context.setActionConfig(action);
					context.setParameters(new ParameterMap(req));
					context.setSession(new SessionMap(req));
					context.setApplication(new ApplicationMap(servletContext));
					context.setAttributes(new HashMap<String, Object>());
					FlashMap flashMap = flashManger.retrieveAndUpdate(req, resp);
					if (flashMap != null) {
						context.setFlash(flashMap);
					} else {
						context.setFlash(new FlashMap());
					}
					ActionContext.setContext(context);

					for (HandlerInterceptor interceptor : interceptors) {
						interceptor.preHandle(req, resp);
					}

					Object result = action.invoke(context);

					for (HandlerInterceptor interceptor : interceptors) {
						interceptor.afterCompletion(req, resp);
					}

					viewResovle.render(result, flashManger, req, resp);
				} catch (Exception e) {
					// TODO Exception 页面
					throw new ServletException(e);
				} finally {
					ActionContext.setContext(null);
				}
			} else {
				chain.doFilter(request, response);
			}
		} else {
			chain.doFilter(request, response);
		}
	}

	@Override
	public void destroy() {

	}

}
